Android 设计模式之—单例模式

Android 设计模式之—单例模式

定义

单例是一种对象的创建方式,他是确保一个类只有一个实例,而且自己实例化并向整个系统提供这个实例

特点

单例类只能有一个实例
单例类必须自己创建自己的唯一实例
单例类必须给其它对象提供这个实例

单例模式创建的方法

  1. 懒汉式,线程不安全
    懒汉式是指在申明对象的时候并不去实例化,而且到使用的时候才会去实例化对象。
    优点:类加载比较快。
    缺点:当多个线程并行调用getIntance()方法的时候,会创建多个对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
       public class Singleton {
    private static Singleton instance;
    private Singleton (){}// 私有构造方法

    public static Singleton getInstance() {//向外提供这个实例
    if (instance == null) {
    instance = new Singleton();//自己创建自己的实例
    }
    return instance;//唯一实例
    }
    }

    2.懒汉式,线程安全
    此种方法解决了上面提到的在多线程中创建多个对象的问题,给getInstance()方法加锁(synchronized)。
    优点:在多线程的情况下,也能保证对象的单一。
    缺点:多线程情况下,每次获取对象都需排队等待获取锁,效率较低。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
       public class Singleton {
    private static Singleton instance;
    private Singleton (){}// 私有构造方法
    public static synchronized Singleton getInstance() {//向外提供这个实例
    if (instance == null) {
    instance = new Singleton();//自己创建自己的实例
    }
    return instance;//唯一实例
    }
    }
    ```

    3.饿汉式,线程安全
    此方法是基于类加载机制避免了多线程情况下的同步问题,在类被装载的时候就将对象实例化。
    优点:没有加锁,对象访问效率更高。
    缺点:类被装载的时候就实例化对象,会导致资源浪费。

public class Singleton{
private static Singleton instance=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
4.双锁双校验,线程安全  
此方法采用懒加载的方式,保证资源的节省,采用双重锁机制,保证多线程下的线程安全和使用效率。
优点:在多线程的情下仍然有保持高性能
缺点: 实现复杂。
```
public class Singleton{
1. private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){//不采用方法锁,保证多线程调用效率。
if(instance==null){
//此处加判断,保证获取对象不会被重复创建
synchronize(Singleton.class){// 类锁,保证多线程下,对象不被重复创建
if(instance==null){
instance=new Singleton();
}

}
}
return instance;
}
}
```
引入volatile 关键字是为了防止指令重排,在构造对象的时候,一般分为以下三步:
1. 分配内存空间
2. 初始化对象
3. 将内存空间地址赋值给对应的引用。

但因为操作系统可以对指令进行重新排序,所以过程可能会变成:

1. 分配内存空间
2. 将内存空间地址赋值给对应的引用
3. 初始化对象
这样的情况下,在多线程时可能会将一个未被初始化的对象给返回,因此我们需要防止这种情况发生,所以需要将变量设置为volatile类型的变量.

5.内部类的 线程安全
此方法是利用静态类只在第一次调用时才加载的特性来实现单例模式,只有在getInstance()方法中才加载内部类,而加载过程是线程安全的。

public class Singleton{
private Singleton(){}
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}

1
2
3

6.枚举,线程安全
此方法是利用了枚举的特性,枚举值只有一个时,其实例也只有一个,并且JAVA中的枚举可以和类一样任意定义方法以及属性,故可以用枚举来实现单例,这也是目前实现单例最优的方式

enum EnumSingleton{
INSTANCE;
public void doSomeThing(){
}
}
`